/*
 * #%L
 * Client
 * %%
 * Copyright (C) 2011 Ractoc.com
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package com.ractoc.opengamefinder.client.plugins;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.ractoc.opengamefinder.api.messages.ChatEnterRoomMessage;
import com.ractoc.opengamefinder.api.messages.GetAvatarMessage;
import com.ractoc.opengamefinder.api.messages.LoginMessage;
import com.ractoc.opengamefinder.api.results.MessageResultsErrorCodes;
import com.ractoc.opengamefinder.api.messages.RegisterMessage;
import com.ractoc.opengamefinder.api.results.ChatEnterRoomMessageResult;
import com.ractoc.opengamefinder.api.results.GetAvatarMessageResult;
import com.ractoc.opengamefinder.client.plugins.messages.GetCachedFilenameMessage;
import com.ractoc.opengamefinder.client.plugins.results.GetCachedFilenameMessageResult;
import com.ractoc.opengamefinder.api.results.LoginMessageResult;
import com.ractoc.opengamefinder.client.plugins.results.RegisterMessageResult;
import com.ractoc.opengamefinder.api.vo.AccountVO;
import com.ractoc.opengamefinder.api.vo.AvatarVO;
import com.ractoc.opengamefinder.client.plugins.messages.CacheByteArrayMessage;
import com.ractoc.opengamefinder.client.plugins.nifty.ScreenType;
import com.ractoc.opengamefinder.client.plugins.results.CacheByteArrayMessageResult;
import com.ractoc.pffj.api.BasePluginMessage;
import com.ractoc.pffj.api.BasePluginMessageResult;
import com.ractoc.pffj.api.PluginLoaderException;
import com.ractoc.pffj.api.PluginMessage;
import com.ractoc.pffj.api.PluginMessageResultListener;
import com.ractoc.pffj.core.PluginController;
import com.ractoc.pffj.core.PluginException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * Handles everything account related, from logging in to registering.
 * @author ractoc
 * @version 0.1
 */
public class AccountPlugin extends BaseClientPlugin {

    private static final String CHAT_PLUGIN = "chatPlugin";
    private static final String CACHE_PLUGIN = "cachePlugin";
    private static final String LOBBY_SCREEN = "lobbyScreen";
    private static Logger logger = Logger.getLogger(AccountPlugin.class.getName());
    private AccountVO account;

    /**
     * Default constructor.
     */
    public AccountPlugin() {
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void load() throws PluginLoaderException {
    }

    /**
     * {@inheritDoc}
     * Currently supports the following Messages:
     * <ul>
     * <li>LoginMessage</li>
     * <li>LoginMessageResult</li>
     * <li>RegisterMessage</li>
     * <li>RegisterMessageResult</li>
     * <li>GetAvatarMessage</li>
     * <li>GetAvatarMessageResult</i>
     * </ul>
     */
    @Override
    public void processMessage(final PluginMessage msg, final PluginMessageResultListener listener) {
        BasePluginMessageResult result = null;
        if (msg instanceof LoginMessage) {
            result = login((BasePluginMessage) msg);
        } else if (msg instanceof LoginMessageResult) {
            result = loggedIn((BasePluginMessage) msg);
        } else if (msg instanceof RegisterMessage) {
            result = register((BasePluginMessage) msg);
        } else if (msg instanceof GetAvatarMessage) {
            result = getAvatar((BasePluginMessage) msg);
        } else if (msg instanceof GetAvatarMessageResult) {
            result = receivedAvatar(msg);
        }
        listener.receivedResult(result);
    }

    /**
     * Set the supplied account value object.
     * @param accountParam The supplied account value object.
     */
    public final void setAccount(final AccountVO accountParam) {
        this.account = accountParam;
    }

    /**
     * return the supplied account value object.
     * @return The supplied account value object.
     */
    public final AccountVO getAccount() {
        return account;
    }

    private BasePluginMessageResult getAvatar(final BasePluginMessage msg) {
        GetAvatarMessage gaMsg = (GetAvatarMessage) msg;
        GetAvatarMessageResult gaResult = new GetAvatarMessageResult();
        gaResult.setErrorCode(MessageResultsErrorCodes.SUCCESS);
        GetCachedFilenameMessageResult gcfResult = new GetCachedFilenameMessageResult();
        try {
            final GetCachedFilenameMessage gcfMsg = new GetCachedFilenameMessage();
            gcfMsg.setFileId(gaMsg.getAvatar().getId());
            gcfMsg.setVersion(gaMsg.getAvatar().getVersion());
            gcfMsg.setType(gaMsg.getAvatar().getType());
            gcfResult = (GetCachedFilenameMessageResult) PluginController.getCurrentPluginController().processMessage(
                    CACHE_PLUGIN, gcfMsg);
            if (gcfResult.getErrorCode() == MessageResultsErrorCodes.CACHED_FILE_NOT_FOUND) {
                // since no cached file is found with the given id/version, the avatar needs to be downloaded.
                sendNetworkMessage(gaResult, msg, this.getPluginId(), this.getPluginId(), false, true);
            } else if (gcfResult.getErrorCode() != MessageResultsErrorCodes.SUCCESS) {
                logger.error("Error loading the cached file.");
            }
            gaResult.setErrorCode(gcfResult.getErrorCode());
            AvatarVO avatar = gaMsg.getAvatar();
            avatar.setFileName(gcfResult.getFilename());
            gaResult.setAvatar(avatar);
        }
        catch (final PluginException e) {
            gaResult.setErrorCode(MessageResultsErrorCodes.INTERNAL_ERROR);
            logger.error("Error sending message through the plugin system: ", e);
        }
        return gaResult;
    }

    private BasePluginMessageResult receivedAvatar(PluginMessage msg) {
        GetAvatarMessageResult gaResult = (GetAvatarMessageResult) msg;
        AvatarVO avatar = gaResult.getAvatar();
        logger.debug("received avatar" + avatar);
        logger.debug("with content " + avatar.getContent());
        logger.debug("content size " + avatar.getContent().length);
        CacheByteArrayMessage cbaMsg = new CacheByteArrayMessage();
        cbaMsg.setFileId(avatar.getId());
        cbaMsg.setVersion(avatar.getVersion());
        cbaMsg.setToCache(avatar.getContent());
        cbaMsg.setType(avatar.getType());
        CacheByteArrayMessageResult cbaResult = null;
        try {
            cbaResult = (CacheByteArrayMessageResult) PluginController.getCurrentPluginController().processMessage(CACHE_PLUGIN, cbaMsg);
            gaResult.setErrorCode(cbaResult.getErrorCode());
        }
        catch (PluginException ex) {
            gaResult.setErrorCode(MessageResultsErrorCodes.INTERNAL_ERROR);
        }
        if (gaResult.getErrorCode() == MessageResultsErrorCodes.SUCCESS) {
            gaResult.getAvatar().setContent(null);
            gaResult.getAvatar().setFileName(cbaResult.getFilename());
        }
        return gaResult;
    }

    private BasePluginMessageResult register(final BasePluginMessage msg) {
        BasePluginMessageResult result;
        result = new RegisterMessageResult();
        final RegisterMessage rMsg = (RegisterMessage) msg;
        if (StringUtils.isEmpty(rMsg.getName())) {
            result.setErrorCode(MessageResultsErrorCodes.NO_USERNAME);
        } else if (StringUtils.isEmpty(rMsg.getPassword())) {
            result.setErrorCode(MessageResultsErrorCodes.NO_PASSWORD);
        } else if (StringUtils.isEmpty(rMsg.getRepeatPassword())) {
            result.setErrorCode(MessageResultsErrorCodes.NO_PASSWORD);
        } else if (!rMsg.getPassword().equals(rMsg.getRepeatPassword())) {
            result.setErrorCode(MessageResultsErrorCodes.PASSWORDS_DO_NOT_MATCH);
        } else {
            if (!StringUtils.isEmpty(rMsg.getAvatarFile())) {
                try {
                    rMsg.setAvatarFileContent(loadAvatarImage(rMsg.getAvatarFile()));
                }
                catch (IOException ex) {
                    logger.error("Error loading avatar image", ex);
                }
            }
            final RegisterMessageResult rResult = new RegisterMessageResult();
            sendNetworkMessage(rResult, rMsg, this.getPluginId(), this.getPluginId(), true, true);
            result.setErrorCode(MessageResultsErrorCodes.SUCCESS);
        }
        return result;
    }

    protected BasePluginMessageResult loggedIn(final PluginMessage msg) {
        final BasePluginMessageResult result = new LoginMessageResult();
        final LoginMessageResult rMsg = (LoginMessageResult) msg;
        if (rMsg.getErrorCode() == MessageResultsErrorCodes.SUCCESS) {
            setAccount(rMsg.getAccountVO());
            logger.info("Logged in successfully.");
            displayScreen(LOBBY_SCREEN, ScreenType.LOGIN);
            // after login we end up in the lobby chat room.
            ChatEnterRoomMessageResult cerResult = new ChatEnterRoomMessageResult();
            try {
                final ChatEnterRoomMessage cerMsg = new ChatEnterRoomMessage();
                cerMsg.setRoomId("lobby");
                cerMsg.setAccount(rMsg.getAccountVO());
                cerMsg.setOutBound(true);
                cerResult = (ChatEnterRoomMessageResult) PluginController.getCurrentPluginController().processMessage(
                        CHAT_PLUGIN, cerMsg);
            }
            catch (final PluginException e) {
                cerResult.setErrorCode(MessageResultsErrorCodes.INTERNAL_ERROR);
                logger.error("Error sending message through the plugin system: ", e);
            }
            if (cerResult.getErrorCode() != MessageResultsErrorCodes.SUCCESS) {
                displayError(cerResult.getErrorCode(), ScreenType.LOGIN);
            }
            result.setErrorCode(cerResult.getErrorCode());
        } else {
            logger.info("Not logged in successfully.");
            displayError(rMsg.getErrorCode(), ScreenType.LOGIN);
        }
        return result;
    }

    private BasePluginMessageResult login(final BasePluginMessage msg) {
        BasePluginMessageResult result;
        result = new LoginMessageResult();
        final LoginMessage lMsg = (LoginMessage) msg;
        if (StringUtils.isEmpty(lMsg.getName())) {
            displayError(MessageResultsErrorCodes.NO_USERNAME, ScreenType.LOGIN);
        } else if (StringUtils.isEmpty(lMsg.getPassword())) {
            displayError(MessageResultsErrorCodes.NO_PASSWORD, ScreenType.LOGIN);
        } else {
            sendNetworkMessage(result, lMsg, this.getPluginId(), this.getPluginId(), true, true);
            if (result.getErrorCode() != MessageResultsErrorCodes.SUCCESS) {
                displayError(result.getErrorCode(), ScreenType.LOGIN);
            }
        }
        return result;
    }

    private byte[] loadAvatarImage(String avatarFile) throws IOException {
        File aFile = new File(avatarFile);
        FileInputStream fis = new FileInputStream(aFile);
        byte[] ba = new byte[(int) aFile.length()];
        fis.read(ba);
        return ba;
    }
}
